home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / workbench / term_4.8 / extras / source / term-source.lha / XPR.c < prev    next >
C/C++ Source or Header  |  1997-07-07  |  54KB  |  2,587 lines

  1. /*
  2. **    XPR.c
  3. **
  4. **    External transfer protocol support routines
  5. **
  6. **    Copyright © 1990-1997 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* Prototypes for local routines. */
  17.  
  18. STATIC BOOL CheckForCarrierLoss(UWORD SerialStatus);
  19. STATIC VOID HandleCarrierLoss(VOID);
  20. STATIC VOID PrintBox(LONG Box, LONG Line, STRPTR String, ...);
  21. STATIC BOOL OpenTransferWindow(VOID);
  22. STATIC LONG CheckAbort(BOOL CheckCarrier);
  23. STATIC STRPTR NewFileName(STRPTR Source, STRPTR Buffer, LONG BufferSize);
  24. STATIC VOID IdentifySource(STRPTR Name, STRPTR BBSName, struct DateStamp *OpenDate);
  25. STATIC LONG GetSeconds(STRPTR String);
  26. STATIC STRPTR TruncateName(STRPTR FileName);
  27. STATIC BOOL IsBlockMappedDevice(struct MsgPort *Handler);
  28. STATIC LONG CalculateBlocks(LONG Size, LONG BlockSize);
  29. STATIC BYTE SerialErrorReport(struct IOExtSer *Request);
  30.  
  31.     /* These variables keep the transferred bytes and transfer
  32.      * time in seconds.
  33.      */
  34.  
  35. STATIC LONG                ByteVal,ByteMax,
  36.                         TimeVal,TimeMax;
  37.  
  38. STATIC LONG                LastTimeDelta,LastPercent;
  39.  
  40.     /* Transfer statistics. */
  41.  
  42. STATIC ULONG            CPS_Minimum,
  43.                         CPS_Maximum,
  44.                         CPS_Average,
  45.                         CPS_Current,
  46.                         CPS_Count,
  47.                         CPS_Last;
  48.  
  49.     /* The file currently being transferred. */
  50.  
  51. STATIC struct Buffer    *CurrentFile;
  52.  
  53.     /* Yet some more flags. */
  54.  
  55. STATIC BOOL                UserWasNotified,            /* User was notified that the file being received will not fit. */
  56.                         CheckSpace,                    /* Check the space left on the destination device? */
  57.                         FileSysTypeWasChecked,        /* Filing system type was checked? */
  58.                         ErrorMessageWasDisplayed,    /* The error message was displayed? */
  59.                         CarrierLossWasDisplayed;    /* The loss of the carrier signal was displayed? */
  60.  
  61.     /* CheckForCarrierLoss(UWORD SerialStatus):
  62.      *
  63.      *    Examine the serial status word and do whatever
  64.      *    may be necessary next.
  65.      */
  66.  
  67. STATIC BOOL
  68. CheckForCarrierLoss(UWORD SerialStatus)
  69. {
  70.     if((SerialStatus & CIAF_COMCD) && Config->SerialConfig->CheckCarrier && !Config->SerialConfig->DirectConnection)
  71.     {
  72.         HandleCarrierLoss();
  73.  
  74.         return(TRUE);
  75.     }
  76.     else
  77.         return(FALSE);
  78. }
  79.  
  80.     /* HandleCarrierLoss():
  81.      *
  82.      *    Do whatever needs to be done in case the carrier signal
  83.      *    is lost during the transmission.
  84.      */
  85.  
  86. STATIC VOID
  87. HandleCarrierLoss()
  88. {
  89.     if(!CarrierLossWasDisplayed)
  90.     {
  91.         CarrierLossWasDisplayed = TRUE;
  92.  
  93.         AddTransferInfo(TRUE,LocaleString(MSG_TERMXPR_CARRIER_LOST_TXT));
  94.     }
  95.  
  96.     SetOnlineState(FALSE,0);
  97.  
  98.     TransferError = TRUE;
  99. }
  100.  
  101.     /* PrintBox(LONG Box,LONG Line,STRPTR String,...):
  102.      *
  103.      *    Update the contents of a text box.
  104.      */
  105.  
  106. STATIC VOID
  107. PrintBox(LONG Box,LONG Line,STRPTR String,...)
  108. {
  109.     UBYTE LocalBuffer[256];
  110.     va_list VarArgs;
  111.  
  112.     va_start(VarArgs,String);
  113.     LimitedVSPrintf(sizeof(LocalBuffer),LocalBuffer,String,VarArgs);
  114.     va_end(VarArgs);
  115.  
  116.     LT_SetAttributes(TransferHandle,Box,
  117.         LABX_Index,    Line,
  118.         LABX_Text,    LocalBuffer,
  119.     TAG_DONE);
  120. }
  121.  
  122.     /* OpenTransferWindow():
  123.      *
  124.      *    Local routine to open the transfer window.
  125.      */
  126.  
  127. STATIC BOOL
  128. OpenTransferWindow()
  129. {
  130.         /* Block window input. */
  131.  
  132.     BlockWindows();
  133.  
  134.         /* Try to open the transfer window panel. */
  135.  
  136.     if(TransferPanel(LocaleString(MSG_TERMXPR_RECEIVE_FILES_TXT)))
  137.     {
  138.             /* Supply the log text. */
  139.  
  140.         LogAction(LocaleString(MSG_TERMXPR_LOGMSG_INITIATE_BINARY_DOWNLOAD_TXT));
  141.  
  142.             /* Return success. */
  143.  
  144.         return(TRUE);
  145.     }
  146.     else
  147.     {
  148.             /* Re-enable window input. */
  149.  
  150.         ReleaseWindows();
  151.  
  152.             /* Return failure. */
  153.  
  154.         return(FALSE);
  155.     }
  156. }
  157.  
  158.     /* CheckAbort(BOOL CheckCarrier):
  159.      *
  160.      *    Check for transfer abort.
  161.      */
  162.  
  163. STATIC LONG
  164. CheckAbort(BOOL CheckCarrier)
  165. {
  166.     struct IntuiMessage    *Message;
  167.     ULONG MsgClass,MsgQualifier;
  168.     struct Gadget *MsgGadget;
  169.     struct Window *MsgWindow;
  170.     UWORD MsgCode;
  171.     LONG Result;
  172.  
  173.     Result = 0;
  174.  
  175.         /* No window available for output? */
  176.  
  177.     if(!TransferWindow)
  178.     {
  179.         if(!OpenTransferWindow())
  180.             return(-1);
  181.     }
  182.  
  183.         /* Are we to check the carrier status? */
  184.  
  185.     if(CheckCarrier)
  186.     {
  187.             /* Return error if carrier is lost. */
  188.  
  189.         if(GetSerialStatus() & CIAF_COMCD)
  190.         {
  191.             HandleCarrierLoss();
  192.  
  193.             return(-1);
  194.         }
  195.     }
  196.  
  197.         /* Process all incoming messages. */
  198.  
  199.     while(Message = (struct IntuiMessage *)GT_GetIMsg(TransferWindow->UserPort))
  200.     {
  201.         MsgClass        = Message->Class;
  202.         MsgQualifier    = Message->Qualifier;
  203.         MsgCode            = Message->Code;
  204.         MsgGadget        = (struct Gadget *)Message->IAddress;
  205.         MsgWindow        = Message->IDCMPWindow;
  206.  
  207.         GT_ReplyIMsg(Message);
  208.  
  209.         if(MsgWindow == TransferWindow)
  210.         {
  211.             if(!Result)
  212.             {
  213.                 LT_HandleInput(TransferHandle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  214.  
  215.                 if(MsgClass == IDCMP_GADGETUP)
  216.                 {
  217.                     switch(MsgGadget->GadgetID)
  218.                     {
  219.                         case GAD_TRANSFER_ABORT:
  220.  
  221.                             LogAction(LocaleString(MSG_TERMXPR_LOGMSG_TRANSFER_ABORTED_TXT));
  222.  
  223.                             TransferAborted = TRUE;
  224.  
  225.                             Result = -1;
  226.  
  227.                             break;
  228.  
  229.                         case GAD_TRANSFER_SKIP:
  230.  
  231.                             LogAction(LocaleString(MSG_TERMXPR_LOGMSG_FILE_SKIPPED_TXT));
  232.  
  233.                             Result = 1;
  234.  
  235.                             break;
  236.  
  237.                         case GAD_TRANSFER_ABORT_FILE:
  238.  
  239.                             LogAction(LocaleString(MSG_TERMXPR_LOGMSG_FILE_ABORTED_TXT));
  240.  
  241.                             Result = 2;
  242.  
  243.                             break;
  244.                     }
  245.                 }
  246.             }
  247.         }
  248.     }
  249.  
  250.     return(Result);
  251. }
  252.  
  253.     /* NewFileName(STRPTR Source,STRPTR Buffer,LONG BufferSize):
  254.      *
  255.      *    Build a valid file and path name, including path
  256.      *    substitution, etc.
  257.      */
  258.  
  259. STATIC STRPTR
  260. NewFileName(STRPTR Source,STRPTR Buffer,LONG BufferSize)
  261. {
  262.     if(Config->TransferConfig->OverridePath && !Uploading)
  263.     {
  264.         if(DownloadPath)
  265.             LimitedStrcpy(BufferSize,Buffer,DownloadPath);
  266.         else
  267.             LimitedStrcpy(BufferSize,Buffer,Config->PathConfig->BinaryDownloadPath);
  268.  
  269.         if(!Buffer[0])
  270.         {
  271.             if(!LocalGetCurrentDirName(Buffer,BufferSize))
  272.                 Buffer[0] = 0;
  273.         }
  274.  
  275.         if(Buffer[0])
  276.         {
  277.             if(AddPart(Buffer,FilePart(Source),BufferSize))
  278.                 return(Buffer);
  279.         }
  280.     }
  281.     else
  282.     {
  283.         if(FilePart(Source) == Source)
  284.         {
  285.             if(LocalGetCurrentDirName(Buffer,BufferSize))
  286.             {
  287.                 if(AddPart(Buffer,Source,BufferSize))
  288.                     return(Buffer);
  289.             }
  290.         }
  291.     }
  292.  
  293.     LimitedStrcpy(BufferSize,Buffer,Source);
  294.  
  295.     return(Source);
  296. }
  297.  
  298.     /* IdentifySource(STRPTR Name,STRPTR BBSName,struct DateStamp *OpenDate):
  299.      *
  300.      *    Attach source information (BBS name, date and time) to a file.
  301.      */
  302.  
  303. STATIC VOID
  304. IdentifySource(STRPTR Name,STRPTR BBSName,struct DateStamp *OpenDate)
  305. {
  306.     UBYTE LocalBuffer[MAX_FILENAME_LENGTH],Time[40],Date[40];
  307.     struct DateTime    DateTime;
  308.  
  309.     CopyMem(OpenDate,&DateTime.dat_Stamp,sizeof(struct DateStamp));
  310.  
  311.         /* Prepare for date conversion. */
  312.  
  313.     DateTime.dat_Format        = FORMAT_DEF;
  314.     DateTime.dat_Flags        = 0;
  315.     DateTime.dat_StrDay        = NULL;
  316.     DateTime.dat_StrDate    = Date;
  317.     DateTime.dat_StrTime    = Time;
  318.  
  319.         /* Convert the date. */
  320.  
  321.     if(DateToStr(&DateTime))
  322.     {
  323.         StripSpaces(BBSName);
  324.         StripSpaces(Date);
  325.         StripSpaces(Time);
  326.  
  327.         if(BBSName[0])
  328.             LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,"%s %s %s",BBSName,Date,Time);
  329.         else
  330.             LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,"%s %s",Date,Time);
  331.  
  332.         SetComment(Name,LocalBuffer);
  333.     }
  334. }
  335.  
  336.     /* GetSeconds(STRPTR String):
  337.      *
  338.      *    Tries to turn a string of the format hh:mm:ss into
  339.      *    an integer number.
  340.      */
  341.  
  342. STATIC LONG
  343. GetSeconds(STRPTR String)
  344. {
  345.     UBYTE Buffer[20];
  346.     LONG Seconds;
  347.  
  348.     memset(Buffer,0,20);
  349.     Seconds = 0;
  350.  
  351.     strcpy(Buffer,String);
  352.  
  353.     Seconds += Atol(&Buffer[6]);
  354.  
  355.     Buffer[5] = 0;
  356.  
  357.     Seconds += Atol(&Buffer[3]) * 60;
  358.  
  359.     Buffer[2] = 0;
  360.  
  361.     Seconds += Atol(&Buffer[0]) * 3600;
  362.  
  363.     return(Seconds);
  364. }
  365.  
  366.     /* TruncateName(STRPTR FileName):
  367.      *
  368.      *    Truncates a file name to a maximum of 48 characters.
  369.      */
  370.  
  371. STATIC STRPTR
  372. TruncateName(STRPTR FileName)
  373. {
  374.     LONG Len;
  375.  
  376.     Len = strlen(FileName);
  377.  
  378.     if(Len > 48)
  379.     {
  380.         LONG i;
  381.  
  382.         for(i = Len - 48 ; i < Len ; i++)
  383.         {
  384.             if(i >= Len - 44 && FileName[i] == '/')
  385.             {
  386.                 STATIC UBYTE NameBuffer[MAX_FILENAME_LENGTH];
  387.  
  388.                 strcpy(NameBuffer,".../");
  389.  
  390.                 LimitedStrcat(sizeof(NameBuffer),NameBuffer,&FileName[i + 1]);
  391.  
  392.                 return(NameBuffer);
  393.             }
  394.         }
  395.     }
  396.  
  397.     return(FileName);
  398. }
  399.  
  400.     /* IsBlockMappedDevice(struct MsgPort *Handler):
  401.      *
  402.      *    See if the lock given points to a block mapped filing
  403.      *    system.
  404.      */
  405.  
  406. STATIC BOOL
  407. IsBlockMappedDevice(struct MsgPort *Handler)
  408. {
  409.     struct DosList *Entry;
  410.     BOOL IsBlockMapped;
  411.  
  412.     IsBlockMapped = FALSE;
  413.  
  414.         /* Find the device the lock belongs to */
  415.  
  416.     Entry = LockDosList(LDF_DEVICES | LDF_READ);
  417.  
  418.     while(Entry = NextDosEntry(Entry,LDF_DEVICES))
  419.     {
  420.         if(Entry->dol_Task == Handler)
  421.         {
  422.             struct FileSysStartupMsg *Startup = (struct FileSysStartupMsg *)BADDR(Entry->dol_misc.dol_handler.dol_Startup);
  423.  
  424.                 /* Plain filing system usually don't */
  425.                 /* use the startup entry */
  426.  
  427.             if(TypeOfMem(Startup))
  428.             {
  429.                 struct DosEnvec    *Environ;
  430.                 STRPTR Name;
  431.  
  432.                 Name    = (STRPTR)BADDR(Startup->fssm_Device);
  433.                 Environ    = (struct DosEnvec *)BADDR(Startup->fssm_Environ);
  434.  
  435.                     /* Valid data in the startup entry? */
  436.  
  437.                 if(TypeOfMem(Name) && TypeOfMem(Environ))
  438.                 {
  439.                     struct IOStdReq Request;
  440.  
  441.                     memset(&Request,0,sizeof(Request));
  442.                     Request.io_Message.mn_Length = sizeof(Request);
  443.  
  444.                         /* Last chance, try to open the device driver */
  445.  
  446.                     if(!OpenDevice(Name + 1,Startup->fssm_Unit,(struct IORequest *)&Request,Startup->fssm_Flags))
  447.                     {
  448.                             /* This is a block mapped filing system */
  449.  
  450.                         IsBlockMapped = TRUE;
  451.  
  452.                         CloseDevice((struct IORequest *)&Request);
  453.  
  454.                         break;
  455.                     }
  456.                 }
  457.             }
  458.         }
  459.     }
  460.  
  461.     UnLockDosList(LDF_DEVICES | LDF_READ);
  462.  
  463.     return(IsBlockMapped);
  464. }
  465.  
  466.     /* CalculateBlocks(LONG Size,LONG BlockSize):
  467.      *
  468.      *    Calculate the number of blocks a file will
  469.      *    occupy if saved to a disk.
  470.      */
  471.  
  472. STATIC LONG
  473. CalculateBlocks(LONG Size,LONG BlockSize)
  474. {
  475.     LONG Blocks,Extension;
  476.     BOOL HasExtension;
  477.  
  478.     Blocks            = 1;        /* One for the file header. */
  479.     Extension        = 0;        /* How many block pointers yet. */
  480.     HasExtension    = FALSE;    /* No extension block yet. */
  481.  
  482.         /* Round to next block. */
  483.  
  484.     Size = ((Size + BlockSize - 1) / BlockSize) * BlockSize;
  485.  
  486.     while(Size)
  487.     {
  488.             /* Add another block. */
  489.  
  490.         Blocks++;
  491.  
  492.             /* Subtract another block. */
  493.  
  494.         Size -= BlockSize;
  495.  
  496.             /* Add another block pointer, if 72 have been
  497.              * added, add another extension block.
  498.              */
  499.  
  500.         if((Extension++) == 72)
  501.         {
  502.                 /* If no extension block has been generated
  503.                  * yet, we were running on the block pointers
  504.                  * of the file header itself.
  505.                  */
  506.  
  507.             if(!HasExtension)
  508.                 HasExtension = TRUE;
  509.             else
  510.                 Blocks++;
  511.  
  512.                 /* Reset extension block counter. */
  513.  
  514.             Extension = 0;
  515.         }
  516.     }
  517.  
  518.     return(Blocks);
  519. }
  520.  
  521.     /* SerialErrorReport(struct IOExtSer *Request):
  522.      *
  523.      *    Report a certain I/O error cause.
  524.      */
  525.  
  526. STATIC BYTE
  527. SerialErrorReport(struct IOExtSer *Request)
  528. {
  529.     STRPTR ErrorMessage;
  530.     BOOL IsFatal;
  531.  
  532.     switch(Request->IOSer.io_Error)
  533.     {
  534.         case SerErr_LineErr:
  535.  
  536.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_HARDWARE_DATA_OVERRUN_TXT);
  537.  
  538.             IsFatal = FALSE;
  539.  
  540.             break;
  541.  
  542.         case SerErr_ParityErr:
  543.  
  544.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_PARITY_ERROR_TXT);
  545.  
  546.             IsFatal = TRUE;
  547.  
  548.             break;
  549.  
  550.         case SerErr_TimerErr:
  551.  
  552.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_TIMER_ERROR_TXT);
  553.  
  554.             IsFatal = FALSE;
  555.  
  556.             break;
  557.  
  558.         case SerErr_BufOverflow:
  559.  
  560.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_READ_BUFFER_OVERFLOWED_TXT);
  561.  
  562.             IsFatal = FALSE;
  563.  
  564.             break;
  565.  
  566.         case SerErr_NoDSR:
  567.  
  568.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_NO_DSR_TXT);
  569.  
  570.             IsFatal = TRUE;
  571.  
  572.             break;
  573.  
  574.         case SerErr_DetectedBreak:
  575.  
  576.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_BREAK_DETECTED_TXT);
  577.  
  578.             IsFatal = TRUE;
  579.  
  580.             break;
  581.  
  582.         default:
  583.  
  584.             ErrorMessage = LocaleString(MSG_TERMXPR_ERROR_UNKNOWN_CAUSE_TXT);
  585.  
  586.             IsFatal = FALSE;
  587.  
  588.             break;
  589.     }
  590.  
  591.     AddTransferInfo(TRUE,LocaleString(MSG_TERMXPR_ERROR_TEMPLATE_TXT),Request->IOSer.io_Error,ErrorMessage);
  592.  
  593.     if(IsFatal)
  594.     {
  595.         TransferError = TRUE;
  596.  
  597.         return(TRUE);
  598.     }
  599.     else
  600.         return(FALSE);
  601. }
  602.  
  603.     /* xpr_fopen(STRPTR FileName,STRPTR AccessMode):
  604.      *
  605.      *    Open a file for random access.
  606.      */
  607.  
  608. LONG SAVE_DS ASM
  609. xpr_fopen(REG(a0) STRPTR FileName,REG(a1) STRPTR AccessMode)
  610. {
  611.     UBYTE RealName[MAX_FILENAME_LENGTH];
  612.     struct Buffer *File;
  613.  
  614.     DB(kprintf("xpr_fopen(\"%s\",\"%s\")\n",FileName,AccessMode));
  615.  
  616.     UserWasNotified                = FALSE;
  617.     CarrierLossWasDisplayed        = FALSE;
  618.     ErrorMessageWasDisplayed    = FALSE;
  619.     FileSysTypeWasChecked        = FALSE;
  620.     CheckSpace                    = TRUE;
  621.     DidTransfer                    = TRUE;
  622.  
  623.         /* Reset transfer counters. */
  624.  
  625.     ByteVal            = 0;
  626.     ByteMax            = 0;
  627.     TimeVal            = 0;
  628.     TimeMax            = 0;
  629.  
  630.     LastTimeDelta    = 0;
  631.     LastPercent        = -1;
  632.  
  633.         /* Reset CPS statistics. */
  634.  
  635.     CPS_Minimum        = (ULONG)~0;
  636.     CPS_Maximum        = 0;
  637.     CPS_Average        = 0;
  638.     CPS_Current        = 0;
  639.     CPS_Count        = 0;
  640.     CPS_Last        = 0;
  641.  
  642.         /* No window available for output? */
  643.  
  644.     if(!TransferWindow)
  645.         OpenTransferWindow();
  646.  
  647.     if(OriginalName[0])
  648.     {
  649.         if(!Stricmp(ShrunkenName,FileName))
  650.             FileName = OriginalName;
  651.     }
  652.  
  653.         /* Determine the file name. */
  654.  
  655.     FileName = NewFileName(FileName,RealName,sizeof(RealName));
  656.  
  657.         /* Determine file transfer mode... */
  658.  
  659.     if(File = BufferOpen(FileName,AccessMode))
  660.     {
  661.         switch(AccessMode[0])
  662.         {
  663.             case 'r':
  664.  
  665.                 LogAction(LocaleString(MSG_TERMXPR_LOGMSG_SEND_FILE_TXT),FileName);
  666.                 break;
  667.  
  668.             case 'w':
  669.  
  670.                 LogAction(LocaleString(MSG_TERMXPR_LOGMSG_RECEIVE_FILE_TXT),FileName);
  671.                 break;
  672.  
  673.             case 'a':
  674.  
  675.                 LogAction(LocaleString(MSG_TERMXPR_LOGMSG_UPDATE_FILE_TXT),FileName);
  676.                 break;
  677.         }
  678.  
  679.         CurrentFile = File;
  680.     }
  681.  
  682.     return((LONG)File);
  683. }
  684.  
  685.     /* xpr_fclose(struct Buffer *File):
  686.      *
  687.      *    Close a file opened by xpr_fopen.
  688.      */
  689.  
  690. LONG SAVE_DS ASM
  691. xpr_fclose(REG(a0) struct Buffer *File)
  692. {
  693.     UBYTE RealName[MAX_FILENAME_LENGTH];
  694.     struct DateStamp OpenDate;
  695.     BOOL WriteAccess,Used;
  696.  
  697.     DB(kprintf("xpr_fclose(0x%08lx)\n",File));
  698.  
  699.         /* This happened only once so far, but... */
  700.  
  701.     if(!File)
  702.     {
  703.         CurrentFile = NULL;
  704.  
  705.         return(1);
  706.     }
  707.  
  708.         /* Save some information. */
  709.  
  710.     OpenDate    = File->OpenDate;
  711.     WriteAccess    = File->WriteAccess;
  712.     Used        = File->Used;
  713.  
  714.         /* Get the name of the file. */
  715.  
  716.     if(!NameFromFH(File->FileHandle,RealName,sizeof(RealName)))
  717.         RealName[0] = 0;
  718.  
  719.         /* Close the file and see what it brings... */
  720.  
  721.     if(BufferClose(File) && RealName[0])
  722.     {
  723.             /* Did any access take place at all?
  724.              * xprzmodem.library for example just
  725.              * opens and closes a file in order to
  726.              * see if it exists.
  727.              */
  728.  
  729.         if(!Used)
  730.             LogAction(LocaleString(MSG_TERMXPR_CLOSE_FILE_TXT),RealName);
  731.         else
  732.         {
  733.                 /* Did we receive or send a file? */
  734.  
  735.             if(WriteAccess)
  736.             {
  737.                 LONG Size;
  738.  
  739.                     /* Did the file remain empty? */
  740.  
  741.                 if(!(Size = GetFileSize(RealName)))
  742.                 {
  743.                     AddTransferInfo(TRUE,LocaleString(MSG_TERMXPR_FILE_REMOVED_TXT),FilePart(RealName));
  744.  
  745.                         /* Delete empty file. */
  746.  
  747.                     if(DeleteFile(RealName))
  748.                         LogAction(LocaleString(MSG_TERMXPR_CLOSE_FILE_REMOVED_TXT),RealName);
  749.                     else
  750.                         LogAction(LocaleString(MSG_TERMXPR_CLOSE_FILE_TXT),RealName);
  751.                 }
  752.                 else
  753.                 {
  754.                     struct Node *SomeNode;
  755.  
  756.                     if(ByteMax)
  757.                     {
  758.                         if(Size >= ByteMax)
  759.                             AddTransferInfo(FALSE,LocaleString(MSG_TERMXPR_FILE_RECEIVED_TXT),FilePart(RealName));
  760.                         else
  761.                             AddTransferInfo(TRUE,LocaleString(MSG_TERMXPR_INCOMPLETE_FILE_RECEIVED_TXT),FilePart(RealName));
  762.                     }
  763.  
  764.                         /* Try to identify the file type. */
  765.  
  766.                     if(Config->TransferConfig->IdentifyCommand[0])
  767.                     {
  768.                         UBYTE LocalBuffer[2 * MAX_FILENAME_LENGTH];
  769.                         LONG i;
  770.                         BOOL GotIt;
  771.  
  772.                         GotIt = FALSE;
  773.  
  774.                         for(i = 0 ; i < strlen(Config->TransferConfig->IdentifyCommand) - 1 ; i++)
  775.                         {
  776.                             if(Config->TransferConfig->IdentifyCommand[i] == '%' && Config->TransferConfig->IdentifyCommand[i+1] == 's')
  777.                             {
  778.                                 GotIt = TRUE;
  779.                                 break;
  780.                             }
  781.                         }
  782.  
  783.                         if(GotIt)
  784.                             LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,Config->TransferConfig->IdentifyCommand,RealName);
  785.                         else
  786.                         {
  787.                             LimitedStrcpy(sizeof(LocalBuffer),LocalBuffer,Config->TransferConfig->IdentifyCommand);
  788.                             LimitedStrcat(sizeof(LocalBuffer),LocalBuffer," \"");
  789.                             LimitedStrcat(sizeof(LocalBuffer),LocalBuffer,RealName);
  790.                             LimitedStrcat(sizeof(LocalBuffer),LocalBuffer,"\"");
  791.                         }
  792.  
  793.                         LaunchCommandAsync(LocalBuffer);
  794.                     }
  795.                     else
  796.                     {
  797.                         switch(Config->TransferConfig->IdentifyFiles)
  798.                         {
  799.                             case IDENTIFY_IGNORE:
  800.  
  801.                                 if(Config->MiscConfig->CreateIcons)
  802.                                     Identify(RealName,FALSE);
  803.  
  804.                                 break;
  805.  
  806.                             case IDENTIFY_FILETYPE:
  807.  
  808.                                 Identify(RealName,TRUE);
  809.                                 break;
  810.  
  811.                             case IDENTIFY_SOURCE:
  812.  
  813.                                 IdentifySource(RealName,CurrentBBSName,&OpenDate);
  814.  
  815.                                 if(Config->MiscConfig->CreateIcons)
  816.                                     Identify(RealName,FALSE);
  817.  
  818.                                 break;
  819.                         }
  820.                     }
  821.  
  822.                     if(CPS_Minimum == (ULONG)~0)
  823.                         CPS_Minimum = 0;
  824.  
  825.                     if(CPS_Count == 0)
  826.                     {
  827.                         CPS_Average    = 0;
  828.                         CPS_Count    = 1;
  829.                     }
  830.  
  831.                     LogAction(LocaleString(MSG_TERMXPR_CLOSE_FILE_BYTES_TXT),RealName,Size,CPS_Minimum,CPS_Average / CPS_Count,CPS_Maximum);
  832.  
  833.                     if(SomeNode = CreateGenericListNode(0,RealName))
  834.                         AddGenericListNode(GenericListTable[GLIST_DOWNLOAD],SomeNode,ADD_GLIST_BOTTOM,FALSE);
  835.                 }
  836.             }
  837.             else
  838.             {
  839.                     /* Set the archived bit on files we uploaded? */
  840.  
  841.                 if(Config->TransferConfig->SetArchivedBit)
  842.                     AddProtection(RealName,FIBF_ARCHIVE);
  843.  
  844.                 AddTransferInfo(FALSE,LocaleString(MSG_TERMXPR_FILE_SENT_TXT),FilePart(RealName));
  845.  
  846.                 LogAction(LocaleString(MSG_TERMXPR_CLOSE_FILE_TXT),RealName);
  847.  
  848.                 RemoveUploadListItem(RealName);
  849.             }
  850.         }
  851.     }
  852.  
  853.     CurrentFile = NULL;
  854.  
  855.     return(1);
  856. }
  857.  
  858.     /* xpr_fread(APTR Buffer,LONG Size,LONG Count,struct Buffer *File):
  859.      *
  860.      *    Read a few bytes from a file.
  861.      */
  862.  
  863. LONG SAVE_DS ASM
  864. xpr_fread(REG(a0) APTR Buffer,REG(d0) LONG Size,REG(d1) LONG Count,REG(a1) struct Buffer *File)
  865. {
  866.     DB(kprintf("xpr_fread(0x%08lx,%ld,%ld,0x%08lx)\n",Buffer,Size,Count,File));
  867.  
  868.     return(BufferRead(File,Buffer,Size * Count) / Size);
  869. }
  870.  
  871.     /* xpr_fwrite(APTR Buffer,LONG Size,LONG Count,struct Buffer *File):
  872.      *
  873.      *    Write a few bytes to a file.
  874.      */
  875.  
  876. LONG SAVE_DS ASM
  877. xpr_fwrite(REG(a0) APTR Buffer,REG(d0) LONG Size,REG(d1) LONG Count,REG(a1) struct Buffer *File)
  878. {
  879.     DB(kprintf("xpr_fwrite(0x%08lx,%ld,%ld,0x%08lx)\n",Buffer,Size,Count,File));
  880.  
  881.     return(BufferWrite(File,Buffer,Size * Count) / Size);
  882. }
  883.  
  884.     /* xpr_fseek(struct Buffer *File,LONG Offset,LONG Origin):
  885.      *
  886.      *    Move the read/write pointer in a file.
  887.      */
  888.  
  889. LONG SAVE_DS ASM
  890. xpr_fseek(REG(a0) struct Buffer *File,REG(d0) LONG Offset,REG(d1) LONG Origin)
  891. {
  892.     DB(kprintf("xpr_fseek(0x%08lx,%ld,%ld)\n",File,Offset,Origin));
  893.  
  894.     return(BufferSeek(File,Offset,Origin) ? 0 : -1);
  895. }
  896.  
  897.     /* xpr_sread(APTR Buffer,LONG Size,LONG Timeout):
  898.      *
  899.      *    Read a few bytes from the serial port (including
  900.      *    timeouts).
  901.      */
  902.  
  903. LONG SAVE_DS ASM
  904. xpr_sread(REG(a0) APTR Buffer,REG(d0) ULONG Size,REG(d1) ULONG Timeout)
  905. {
  906.     DB(kprintf("xpr_sread(0x%08lx,%ld,%ld)\n",Buffer,Size,Timeout));
  907.  
  908.         /* No window available for output? */
  909.  
  910.     if(!TransferWindow)
  911.     {
  912.         if(!OpenTransferWindow())
  913.             return(-1);
  914.     }
  915.  
  916.         /* Are both IORequests available? */
  917.  
  918.     if(WriteRequest && ReadRequest)
  919.     {
  920.             /* Valid size parameter? */
  921.  
  922.         if(Size > 0)
  923.         {
  924.             ULONG SignalSet,SerialMask,WindowMask;
  925.             ULONG Waiting;
  926.             UWORD Status;
  927.  
  928.             GetSerialInfo(&Waiting,&Status);
  929.  
  930.                 /* Return error if carrier is lost. */
  931.  
  932.             if(CheckForCarrierLoss(Status))
  933.                 return(-1);
  934.  
  935.                 /* Is there data waiting to be read? */
  936.  
  937.             if(Waiting > 0)
  938.             {
  939.                     /* No timeout specified? Read as many
  940.                      * bytes as available.
  941.                      */
  942.  
  943.                 if(Timeout == 0)
  944.                 {
  945.                     if(Waiting > Size)
  946.                         Waiting = Size;
  947.  
  948.                     if(DoSerialRead(Buffer,Waiting))
  949.                     {
  950.                         if(SerialErrorReport(ReadRequest))
  951.                             return(-1);
  952.                         else
  953.                             Waiting = ReadRequest->IOSer.io_Actual;
  954.                     }
  955.  
  956.                     BytesIn += Waiting;
  957.  
  958.                     return((LONG)Waiting);
  959.                 }
  960.  
  961.                     /* Enough data pending to be read? */
  962.  
  963.                 if(Waiting >= Size)
  964.                 {
  965.                     if(DoSerialRead(Buffer,Size))
  966.                     {
  967.                         if(SerialErrorReport(ReadRequest))
  968.                             return(-1);
  969.                         else
  970.                             Size = ReadRequest->IOSer.io_Actual;
  971.                     }
  972.  
  973.                     BytesIn += Size;
  974.  
  975.                     return((LONG)Size);
  976.                 }
  977.             }
  978.             else
  979.             {
  980.                     /* No timeout and no data available:
  981.                      * return immediately.
  982.                      */
  983.  
  984.                 if(Timeout == 0)
  985.                     return(0);
  986.             }
  987.  
  988.                 /* Set up the timer. */
  989.  
  990.             StartTime(Timeout / MILLION,Timeout % MILLION);
  991.  
  992.                 /* Set up the read request. */
  993.  
  994.             StartSerialRead(Buffer,Size);
  995.  
  996.                 /* We'll need them in a minute */
  997.  
  998.             SerialMask = PORTMASK(ReadPort);
  999.             WindowMask = PORTMASK(TransferWindow->UserPort);
  1000.  
  1001.             while(TRUE)
  1002.             {
  1003.                 SignalSet = Wait(SerialMask | SIG_TIMER | WindowMask);
  1004.  
  1005.                     /* Abort the file transfer? */
  1006.  
  1007.                 if(SignalSet & WindowMask)
  1008.                 {
  1009.                     LONG Result = CheckAbort(FALSE);
  1010.  
  1011.                         /* Let's get out of here
  1012.                          * and hope that the protocol
  1013.                          * will call xpr_chkabort()
  1014.                          * in time.
  1015.                          */
  1016.  
  1017.                     if(Result != 0)
  1018.                     {
  1019.                         TransferAbortState = Result;
  1020.  
  1021.                             /* Stop whatever we were doing. */
  1022.  
  1023.                         StopSerialRead();
  1024.                         StopTime();
  1025.  
  1026.                             /* Does the user want to cancel
  1027.                              * the transmission?
  1028.                              */
  1029.  
  1030.                         if(Result < 0)
  1031.                         {
  1032.                                 /* Do it the hard way */
  1033.  
  1034.                             if(TransferAbortCount++)
  1035.                                 CancelZModem();
  1036.  
  1037.                             return(Result);
  1038.                         }
  1039.                         else
  1040.                         {
  1041.                                 /* So it's something else. Pick up whatever
  1042.                                  * we received and return immediately.
  1043.                                  */
  1044.  
  1045.                             if(ReadRequest->IOSer.io_Actual > 0)
  1046.                             {
  1047.                                 BytesIn += ReadRequest->IOSer.io_Actual;
  1048.  
  1049.                                 return((LONG)ReadRequest->IOSer.io_Actual);
  1050.                             }
  1051.                             else
  1052.                             {
  1053.                                     /* Take a second look and query the number of
  1054.                                      * bytes ready to be received, there may
  1055.                                      * still be some bytes in the buffer.
  1056.                                      * Note: this depends on the way the
  1057.                                      * driver handles read abort.
  1058.                                      */
  1059.  
  1060.                                 GetSerialInfo(&Waiting,&Status);
  1061.  
  1062.                                     /* Don't read too much. */
  1063.  
  1064.                                 if(Size > Waiting)
  1065.                                     Size = Waiting;
  1066.  
  1067.                                     /* Are there any bytes to be transferred? */
  1068.  
  1069.                                 if(Size > 0)
  1070.                                 {
  1071.                                         /* Read the data. */
  1072.  
  1073.                                     if(DoSerialRead(Buffer,Size))
  1074.                                     {
  1075.                                         if(SerialErrorReport(ReadRequest))
  1076.                                             return(-1);
  1077.                                         else
  1078.                                             Size = ReadRequest->IOSer.io_Actual;
  1079.                                     }
  1080.  
  1081.                                     BytesIn += Size;
  1082.                                 }
  1083.                                 else
  1084.                                 {
  1085.                                         /* Ok, so there is no data in the buffer. */
  1086.                                         /* Check if the carrier signal is still */
  1087.                                         /* present */
  1088.  
  1089.                                     if(CheckForCarrierLoss(Status))
  1090.                                         return(-1);
  1091.                                 }
  1092.  
  1093.                                 return((LONG)Size);
  1094.                             }
  1095.                         }
  1096.                     }
  1097.                 }
  1098.  
  1099.                     /* Receive buffer filled? */
  1100.  
  1101.                 if(SignalSet & SerialMask)
  1102.                 {
  1103.                         /* Abort the timer request. */
  1104.  
  1105.                     StopTime();
  1106.  
  1107.                         /* Did the request terminate gracefully? */
  1108.  
  1109.                     if(WaitSerialRead())
  1110.                     {
  1111.                         if(SerialErrorReport(ReadRequest))
  1112.                             return(-1);
  1113.                         else
  1114.                             Size = ReadRequest->IOSer.io_Actual;
  1115.                     }
  1116.  
  1117.                     BytesIn += Size;
  1118.  
  1119.                     return((LONG)Size);
  1120.                 }
  1121.  
  1122.                     /* Hit by timeout? */
  1123.  
  1124.                 if(SignalSet & SIG_TIMER)
  1125.                 {
  1126.                         /* Abort the read request. */
  1127.  
  1128.                     StopSerialRead();
  1129.  
  1130.                         /* Remove the timer request. */
  1131.  
  1132.                     WaitTime();
  1133.  
  1134.                         /* Did the driver receive any
  1135.                          * data?
  1136.                          */
  1137.  
  1138.                     if(ReadRequest->IOSer.io_Actual > 0)
  1139.                     {
  1140.                         BytesIn += ReadRequest->IOSer.io_Actual;
  1141.  
  1142.                         return((LONG)ReadRequest->IOSer.io_Actual);
  1143.                     }
  1144.                     else
  1145.                     {
  1146.                             /* Take a second look and query the number of
  1147.                              * bytes ready to be received, there may
  1148.                              * still be some bytes in the buffer.
  1149.                              * Note: this depends on the way the
  1150.                              * driver handles read abort.
  1151.                              */
  1152.  
  1153.                         GetSerialInfo(&Waiting,&Status);
  1154.  
  1155.                             /* Don't read too much. */
  1156.  
  1157.                         if(Size > Waiting)
  1158.                             Size = Waiting;
  1159.  
  1160.                             /* Are there any bytes to be transferred? */
  1161.  
  1162.                         if(Size > 0)
  1163.                         {
  1164.                                 /* Read the data. */
  1165.  
  1166.                             if(DoSerialRead(Buffer,Size))
  1167.                             {
  1168.                                 if(SerialErrorReport(ReadRequest))
  1169.                                     return(-1);
  1170.                                 else
  1171.                                     Size = ReadRequest->IOSer.io_Actual;
  1172.                             }
  1173.  
  1174.                             BytesIn += Size;
  1175.                         }
  1176.                         else
  1177.                         {
  1178.                                 /* Ok, so there is no data in the buffer. */
  1179.                                 /* Check if the carrier signal is still */
  1180.                                 /* present */
  1181.  
  1182.                             if(CheckForCarrierLoss(Status))
  1183.                                 return(-1);
  1184.                         }
  1185.  
  1186.                         return((LONG)Size);
  1187.                     }
  1188.                 }
  1189.             }
  1190.         }
  1191.         else
  1192.             return(0);
  1193.     }
  1194.     else
  1195.         return(-1);
  1196. }
  1197.  
  1198.     /* xpr_swrite(APTR Buffer,LONG Size):
  1199.      *
  1200.      *    Write a few bytes to the serial port.
  1201.      */
  1202.  
  1203. LONG SAVE_DS ASM
  1204. xpr_swrite(REG(a0) APTR Buffer,REG(d0) LONG Size)
  1205. {
  1206.     DB(kprintf("xpr_swrite(0x%08lx,%ld)\n",Buffer,Size));
  1207.  
  1208.         /* Return error if carrier is lost. */
  1209.  
  1210.     if(WriteRequest && !CheckForCarrierLoss(GetSerialStatus()))
  1211.     {
  1212.             /* Send the data. */
  1213.  
  1214.         if(!DoSerialWrite(Buffer,Size))
  1215.             BytesOut += Size;
  1216.         else
  1217.         {
  1218.             if(SerialErrorReport(WriteRequest))
  1219.                 return(-1);
  1220.         }
  1221.  
  1222.         return(0);
  1223.     }
  1224.  
  1225.     return(-1);
  1226. }
  1227.  
  1228.     /* xpr_sflush():
  1229.      *
  1230.      *    Release the contents of all serial buffers.
  1231.      */
  1232.  
  1233. LONG SAVE_DS
  1234. xpr_sflush()
  1235. {
  1236.     DB(kprintf("xpr_sflush()\n"));
  1237.  
  1238.     return((LONG)FlushSerialRead());
  1239. }
  1240.  
  1241.     /* xpr_update(struct XPR_UPDATE *UpdateInfo):
  1242.      *
  1243.      *    Update the information displayed in the transfer window.
  1244.      */
  1245.  
  1246. LONG SAVE_DS ASM
  1247. xpr_update(REG(a0) struct XPR_UPDATE *UpdateInfo)
  1248. {
  1249.     STATIC UBYTE RealName[MAX_FILENAME_LENGTH];
  1250.  
  1251.     DB(kprintf("xpr_update(0x%08lx)\n",UpdateInfo));
  1252.  
  1253.         /* No window available for output? */
  1254.  
  1255.     if(!TransferWindow)
  1256.     {
  1257.         if(!OpenTransferWindow())
  1258.             return(0);
  1259.     }
  1260.  
  1261.     RepairRaster();
  1262.  
  1263.     if(UpdateInfo)
  1264.     {
  1265.         BOOL NewByte,NewTime;
  1266.  
  1267.         NewByte    = FALSE;
  1268.         NewTime = FALSE;
  1269.  
  1270.         if(TransferWindow->Flags & WFLG_ZOOMED)
  1271.         {
  1272.             STATIC ULONG LastSeconds;
  1273.  
  1274.             struct timeval Now;
  1275.             BOOL Refresh;
  1276.  
  1277.             GetSysTime(&Now);
  1278.  
  1279.             Refresh = TRUE;
  1280.  
  1281.             if(!TransferZoomed)
  1282.             {
  1283.                 LastSeconds = Now.tv_secs;
  1284.  
  1285.                 TransferZoomed = TRUE;
  1286.             }
  1287.             else
  1288.             {
  1289.                 if(Now.tv_secs > LastSeconds)
  1290.                     LastSeconds = Now.tv_secs;
  1291.                 else
  1292.                     Refresh = FALSE;
  1293.             }
  1294.  
  1295.             if(Refresh)
  1296.             {
  1297.                 STRPTR Template;
  1298.  
  1299.                 if(LastPercent > 0)
  1300.                     Template = "%s [%s %ld%%]";
  1301.                 else
  1302.                     Template = "%s [%s]";
  1303.  
  1304.                 LimitedSPrintf(sizeof(TransferTitleBuffer),TransferTitleBuffer,Template,TransferWindowTitle,TruncateName(RealName),LastPercent);
  1305.  
  1306.                 SetWindowTitles(TransferWindow,TransferTitleBuffer,(STRPTR)-1);
  1307.             }
  1308.         }
  1309.         else
  1310.         {
  1311.             if(TransferZoomed)
  1312.             {
  1313.                 SetWindowTitles(TransferWindow,TransferWindowTitle,(STRPTR)-1);
  1314.  
  1315.                 TransferZoomed = FALSE;
  1316.             }
  1317.         }
  1318.  
  1319.         if((UpdateInfo->xpru_updatemask & XPRU_PROTOCOL) && UpdateInfo->xpru_protocol)
  1320.             LT_SetAttributes(TransferHandle,GAD_TRANSFER_PROTOCOL,GTTX_Text,UpdateInfo->xpru_protocol,TAG_DONE);
  1321.  
  1322.         if((UpdateInfo->xpru_updatemask & XPRU_MSG) && UpdateInfo->xpru_msg)
  1323.             AddTransferInfo(FALSE,UpdateInfo->xpru_msg);
  1324.  
  1325.         if((UpdateInfo->xpru_updatemask & XPRU_ERRORMSG) && UpdateInfo->xpru_errormsg)
  1326.             AddTransferInfo(TRUE,UpdateInfo->xpru_errormsg);
  1327.  
  1328.         if((UpdateInfo->xpru_updatemask & XPRU_FILENAME) && UpdateInfo->xpru_filename)
  1329.         {
  1330.             STRPTR FileName = UpdateInfo->xpru_filename;
  1331.  
  1332.             if(OriginalName[0])
  1333.             {
  1334.                 if(!Stricmp(ShrunkenName,FileName))
  1335.                     FileName = OriginalName;
  1336.             }
  1337.  
  1338.             FileName = NewFileName(FileName,RealName,sizeof(RealName));
  1339.  
  1340.             LT_SetAttributes(TransferHandle,GAD_TRANSFER_FILE,LABX_Index,0,LABX_Text,TruncateName(FileName),TAG_DONE);
  1341.  
  1342.             if(FileTransferInfo)
  1343.             {
  1344.                 LONG Percentage;
  1345.  
  1346.                 if(FileTransferInfo->CurrentFile)
  1347.                 {
  1348.                     struct FileTransferNode *Node;
  1349.                     STRPTR Name;
  1350.  
  1351.                     Node = (struct FileTransferNode *)FileTransferInfo->CurrentFile->MinNode.mln_Succ;
  1352.  
  1353.                     if(Node->MinNode.mln_Succ)
  1354.                         Name = TruncateName(Node->Name);
  1355.                     else
  1356.                         Name = "-";
  1357.  
  1358.                     LT_SetAttributes(TransferHandle,GAD_TRANSFER_FILE,LABX_Index,1,LABX_Text,Name,TAG_DONE);
  1359.                 }
  1360.  
  1361.                 PrintBox(GAD_TRANSFER_SIZE,2,ConvNumber,FileTransferInfo->TotalSize);
  1362.  
  1363.                 if(FileTransferInfo->TotalFiles)
  1364.                     Percentage = (100 * FileTransferInfo->DoneFiles) / FileTransferInfo->TotalFiles;
  1365.                 else
  1366.                     Percentage = 0;
  1367.  
  1368.                 PrintBox(GAD_TRANSFER_SIZE,4,LocaleString(MSG_TRANSFERPANEL_NUMBER_TO_GO_PERCENT_TXT),FileTransferInfo->DoneFiles,FileTransferInfo->TotalFiles,Percentage);
  1369.             }
  1370.         }
  1371.  
  1372.         if((UpdateInfo->xpru_updatemask & XPRU_FILESIZE) && UpdateInfo->xpru_filesize != -1)
  1373.         {
  1374.             STRPTR FormatSpecifier;
  1375.  
  1376.             if(CurrentFile && CurrentFile->InfoPort)
  1377.                 FormatSpecifier = ConvNumber10;
  1378.             else
  1379.                 FormatSpecifier = ConvNumber;
  1380.  
  1381.             PrintBox(GAD_TRANSFER_SIZE,0,FormatSpecifier,UpdateInfo->xpru_filesize);
  1382.  
  1383.             if(ByteMax = UpdateInfo->xpru_filesize)
  1384.                 NewByte = TRUE;
  1385.         }
  1386.  
  1387.         if((UpdateInfo->xpru_updatemask & XPRU_BYTES) && UpdateInfo->xpru_bytes != -1)
  1388.         {
  1389.             STRPTR FormatSpecifier;
  1390.  
  1391.             if(CurrentFile && CurrentFile->InfoPort)
  1392.                 FormatSpecifier = ConvNumber10;
  1393.             else
  1394.                 FormatSpecifier = ConvNumber;
  1395.  
  1396.             PrintBox(GAD_TRANSFER_SIZE,1,FormatSpecifier,ByteVal = UpdateInfo->xpru_bytes);
  1397.  
  1398.             if(FileTransferInfo)
  1399.             {
  1400.                 LONG Percentage;
  1401.                 ULONG Len;
  1402.  
  1403.                 Len = FileTransferInfo->DoneSize + UpdateInfo->xpru_bytes;
  1404.  
  1405.                 if(FileTransferInfo->TotalSize)
  1406.                     Percentage = (100 * Len) / FileTransferInfo->TotalSize;
  1407.                 else
  1408.                     Percentage = 0;
  1409.  
  1410.                 PrintBox(GAD_TRANSFER_SIZE,3,LocaleString(MSG_TRANSFERPANEL_NUMBER_PERCENT_TXT),Len,Percentage);
  1411.             }
  1412.  
  1413.             if(ByteMax)
  1414.                 NewByte = TRUE;
  1415.  
  1416.             if(CurrentFile)
  1417.             {
  1418.                 if(CurrentFile->InfoPort && !Uploading)
  1419.                 {
  1420.                     if(CurrentFile->InfoData.id_NumBlocks && CurrentFile->InfoData.id_BytesPerBlock)
  1421.                     {
  1422.                         LONG DisplaySpace,DisplayPercent;
  1423.                         STRPTR DisplayMessage;
  1424.  
  1425.                         DisplayMessage    = "";
  1426.                         DisplayPercent    = (100 * CurrentFile->InfoData.id_NumBlocksUsed) / CurrentFile->InfoData.id_NumBlocks;
  1427.                         DisplaySpace    = CurrentFile->InfoData.id_NumBlocks - CurrentFile->InfoData.id_NumBlocksUsed;
  1428.  
  1429.                         if(ByteMax && (CheckSpace || !FileSysTypeWasChecked))
  1430.                         {
  1431.                                 /* Did we take a look at the filing system yet? */
  1432.  
  1433.                             if(!FileSysTypeWasChecked)
  1434.                             {
  1435.                                 FileSysTypeWasChecked = TRUE;
  1436.  
  1437.                                     /* If this is not a block mapped device */
  1438.                                     /* we cannot guess what will happen if */
  1439.                                     /* it fills up (and whether it fills up at all). */
  1440.  
  1441.                                 if(!IsBlockMappedDevice(CurrentFile->InfoPort))
  1442.                                     CheckSpace = FALSE;
  1443.                             }
  1444.  
  1445.                                 /* Should we check the space left on the destination device? */
  1446.  
  1447.                             if(CheckSpace)
  1448.                             {
  1449.                                     /* Important! Only use the number of bytes still */
  1450.                                     /* to be transferred. */
  1451.  
  1452.                                 LONG Blocks = CalculateBlocks(ByteMax - ByteVal,CurrentFile->InfoData.id_BytesPerBlock);
  1453.  
  1454.                                     /* Is there less space left than we need? */
  1455.  
  1456.                                 if(DisplaySpace < Blocks)
  1457.                                 {
  1458.                                     if(!UserWasNotified)
  1459.                                     {
  1460.                                         UserWasNotified = TRUE;
  1461.  
  1462.                                         Say(LocaleString(MSG_TERMXPR_SAY_FILE_MAY_NOT_FIT_TXT));
  1463.                                     }
  1464.  
  1465.                                     DisplayMessage = LocaleString(MSG_TERMXPR_FILE_MAY_NOT_FIT_TXT);
  1466.                                 }
  1467.                             }
  1468.                         }
  1469.  
  1470.                         PrintBox(GAD_TRANSFER_FILE,2,LocaleString(MSG_TERMXPR_BYTES_FULL_TXT),DisplaySpace * CurrentFile->InfoData.id_BytesPerBlock,DisplayPercent,DisplayMessage);
  1471.                     }
  1472.                 }
  1473.             }
  1474.         }
  1475.  
  1476.         if((UpdateInfo->xpru_updatemask & XPRU_BLOCKS) && UpdateInfo->xpru_blocks != -1)
  1477.             PrintBox(GAD_TRANSFER_SIZE,5,ConvNumber,UpdateInfo->xpru_blocks);
  1478.  
  1479.         if((UpdateInfo->xpru_updatemask & XPRU_DATARATE) && UpdateInfo->xpru_datarate > 0)
  1480.         {
  1481.             LONG Change;
  1482.  
  1483.             CPS_Current = UpdateInfo->xpru_datarate;
  1484.  
  1485.             if(CPS_Last)
  1486.             {
  1487.                 if(CPS_Last < UpdateInfo->xpru_datarate)
  1488.                     Change = (100 * (UpdateInfo->xpru_datarate - CPS_Last)) / CPS_Last;
  1489.                 else
  1490.                     Change = (100 * (CPS_Last - UpdateInfo->xpru_datarate)) / CPS_Last;
  1491.             }
  1492.             else
  1493.                 Change = 100;
  1494.  
  1495.             if(Change > 1)
  1496.             {
  1497.                 PrintBox(GAD_TRANSFER_SECONDS,0,ConvNumber,UpdateInfo->xpru_datarate);
  1498.  
  1499.                 CPS_Last = UpdateInfo->xpru_datarate;
  1500.             }
  1501.  
  1502.             if(UpdateInfo->xpru_datarate < CPS_Minimum)
  1503.                 CPS_Minimum = UpdateInfo->xpru_datarate;
  1504.  
  1505.             if(UpdateInfo->xpru_datarate > CPS_Maximum)
  1506.                 CPS_Maximum = UpdateInfo->xpru_datarate;
  1507.  
  1508.             if((ULONG)(CPS_Average + UpdateInfo->xpru_datarate) >= CPS_Average)
  1509.             {
  1510.                 CPS_Average += UpdateInfo->xpru_datarate;
  1511.  
  1512.                 CPS_Count++;
  1513.             }
  1514.         }
  1515.  
  1516.         if((UpdateInfo->xpru_updatemask & XPRU_CHARDELAY) && UpdateInfo->xpru_chardelay != -1)
  1517.             PrintBox(GAD_TRANSFER_SECONDS,1,ConvNumber,UpdateInfo->xpru_chardelay);
  1518.  
  1519.         if((UpdateInfo->xpru_updatemask & XPRU_PACKETDELAY) && UpdateInfo->xpru_packetdelay != -1)
  1520.             PrintBox(GAD_TRANSFER_SECONDS,2,ConvNumber,UpdateInfo->xpru_packetdelay);
  1521.  
  1522.         if((UpdateInfo->xpru_updatemask & XPRU_PACKETTYPE) && UpdateInfo->xpru_packettype != -1)
  1523.         {
  1524.             STRPTR FormatSpecifier;
  1525.  
  1526.             FormatSpecifier = ConvNumber;
  1527.  
  1528.             if(UpdateInfo->xpru_packettype > 32 && UpdateInfo->xpru_packettype < 256)
  1529.             {
  1530.                 if(IsPrintable[UpdateInfo->xpru_packettype])
  1531.                     FormatSpecifier = "`%lc'";
  1532.             }
  1533.  
  1534.             PrintBox(GAD_TRANSFER_SECONDS,3,FormatSpecifier,UpdateInfo->xpru_packettype);
  1535.         }
  1536.  
  1537.         if((UpdateInfo->xpru_updatemask & XPRU_BLOCKCHECK) && UpdateInfo->xpru_blockcheck)
  1538.             PrintBox(GAD_TRANSFER_SECONDS,4,UpdateInfo->xpru_blockcheck);
  1539.  
  1540.         if((UpdateInfo->xpru_updatemask & XPRU_BLOCKSIZE) && UpdateInfo->xpru_blocksize != -1)
  1541.             PrintBox(GAD_TRANSFER_SECONDS,5,ConvNumber,UpdateInfo->xpru_blocksize);
  1542.  
  1543.  
  1544.         if((UpdateInfo->xpru_updatemask & XPRU_EXPECTTIME) && UpdateInfo->xpru_expecttime)
  1545.         {
  1546.             PrintBox(GAD_TRANSFER_TOTALTIME,0,UpdateInfo->xpru_expecttime);
  1547.  
  1548.             if(TimeMax = GetSeconds((STRPTR)UpdateInfo->xpru_expecttime))
  1549.                 NewTime = TRUE;
  1550.         }
  1551.  
  1552.         if((UpdateInfo->xpru_updatemask & XPRU_ELAPSEDTIME) && UpdateInfo->xpru_elapsedtime)
  1553.         {
  1554.             PrintBox(GAD_TRANSFER_TOTALTIME,1,UpdateInfo->xpru_elapsedtime);
  1555.  
  1556.             TimeVal = GetSeconds((STRPTR)UpdateInfo->xpru_elapsedtime);
  1557.  
  1558.             if(TimeMax)
  1559.                 NewTime = TRUE;
  1560.         }
  1561.  
  1562.         if((UpdateInfo->xpru_updatemask & XPRU_ERRORS) && UpdateInfo->xpru_errors != -1)
  1563.         {
  1564.             PrintBox(GAD_TRANSFER_ERRORS,0,ConvNumber,UpdateInfo->xpru_errors);
  1565.  
  1566.             if(!ErrorMessageWasDisplayed && Config->TransferConfig->ErrorNotification && UpdateInfo->xpru_errors >= Config->TransferConfig->ErrorNotification)
  1567.             {
  1568.                 ErrorMessageWasDisplayed = TRUE;
  1569.  
  1570.                 WakeUp(TransferWindow,SOUND_ERROR);
  1571.             }
  1572.         }
  1573.  
  1574.         if((UpdateInfo->xpru_updatemask & XPRU_TIMEOUTS) && UpdateInfo->xpru_timeouts != -1)
  1575.             PrintBox(GAD_TRANSFER_ERRORS,1,ConvNumber,UpdateInfo->xpru_timeouts);
  1576.  
  1577.         if(NewByte)
  1578.         {
  1579.             LONG Percent;
  1580.  
  1581.             if(ByteMax)
  1582.                 Percent = (100 * ByteVal) / ByteMax;
  1583.             else
  1584.                 Percent = 0;
  1585.  
  1586.             if(Percent != LastPercent)
  1587.             {
  1588.                 UBYTE LocalBuffer[40];
  1589.  
  1590.                 LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,"%ld%% %s",Percent,LocaleString(MSG_TRANSFERPANEL_DATA_TRANSFERRED_GAD));
  1591.  
  1592.                 LastPercent = Percent;
  1593.  
  1594.                 LT_SetAttributes(TransferHandle,GAD_TRANSFER_PERCENT,
  1595.                     LAGA_Percent,    Percent,
  1596.                     LAGA_InfoText,    LocalBuffer,
  1597.                 TAG_DONE);
  1598.             }
  1599.         }
  1600.  
  1601.         if(NewTime)
  1602.         {
  1603.             LONG TimeDelta,Change;
  1604.  
  1605.             if(TimeVal > TimeMax)
  1606.                 TimeDelta = 0;
  1607.             else
  1608.                 TimeDelta = TimeMax - TimeVal;
  1609.  
  1610.             if(LastTimeDelta)
  1611.             {
  1612.                 if(LastTimeDelta < TimeDelta)
  1613.                     Change = (100 * (TimeDelta - LastTimeDelta)) / LastTimeDelta;
  1614.                 else
  1615.                     Change = (100 * (LastTimeDelta - TimeDelta)) / LastTimeDelta;
  1616.             }
  1617.             else
  1618.                 Change = 100;
  1619.  
  1620.                 /* Don't update the display unless the change
  1621.                  * exceeds 2% of the previous value.
  1622.                  */
  1623.  
  1624.             if(Change > 2)
  1625.             {
  1626.                 UBYTE LocalBuffer[40];
  1627.                 LONG Percent;
  1628.  
  1629.                 LastTimeDelta = TimeDelta;
  1630.  
  1631.                 if(TimeMax)
  1632.                     Percent = (100 * TimeDelta) / TimeMax;
  1633.                 else
  1634.                     Percent = 0;
  1635.  
  1636.                 LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,"%2ld:%02ld:%02ld %s",TimeDelta / 3600,(TimeDelta / 60) % 60,TimeDelta % 60,LocaleString(MSG_TRANSFERPANEL_TIME_TO_GO_GAD));
  1637.  
  1638.                 LT_SetAttributes(TransferHandle,GAD_TRANSFER_TIME,
  1639.                     LAGA_Percent,    Percent,
  1640.                     LAGA_InfoText,    LocalBuffer,
  1641.                 TAG_DONE);
  1642.  
  1643.                     /* A rapidly changing transfer time display would
  1644.                      * cause the transfer completion time display to
  1645.                      * change at the same pace. As the completion time
  1646.                      * display calculation is rather costly, a change smaller
  1647.                      * than 5% of the previous value is silently ignored.
  1648.                      */
  1649.  
  1650.                 if(Change > 5)
  1651.                 {
  1652.                     UBYTE DateTimeBuffer[256];
  1653.                     struct DateStamp Stamp;
  1654.  
  1655.                         /* Obtain current time. */
  1656.  
  1657.                     CurrentTimeToStamp(&Stamp);
  1658.  
  1659.                         /* Add the time to go. */
  1660.  
  1661.                     Stamp.ds_Tick    += (TimeDelta % 60) * TICKS_PER_SECOND;
  1662.                     Stamp.ds_Minute    += TimeDelta / 60 + Stamp.ds_Tick / (60 * TICKS_PER_SECOND);
  1663.                     Stamp.ds_Days    += Stamp.ds_Minute / 1440;
  1664.  
  1665.                     Stamp.ds_Tick    %= 60 * TICKS_PER_SECOND;
  1666.                     Stamp.ds_Minute    %= 1440;
  1667.  
  1668.                         /* Conversion succeeded? */
  1669.  
  1670.                     if(FormatStamp(&Stamp,DateTimeBuffer,sizeof(DateTimeBuffer),TRUE))
  1671.                         PrintBox(GAD_TRANSFER_FILE,3,DateTimeBuffer);
  1672.                 }
  1673.             }
  1674.         }
  1675.     }
  1676.  
  1677.     return(1);
  1678. }
  1679.  
  1680.     /* xpr_chkabort():
  1681.      *
  1682.      *    Check if the user has aborted the transfer.
  1683.      */
  1684.  
  1685. LONG SAVE_DS
  1686. xpr_chkabort()
  1687. {
  1688.     LONG Result;
  1689.  
  1690.     DB(kprintf("xpr_chkabort()\n"));
  1691.  
  1692.     if(TransferAbortState != 0)
  1693.     {
  1694.         Result = TransferAbortState;
  1695.  
  1696.         TransferAbortState = 0;
  1697.     }
  1698.     else
  1699.         Result = CheckAbort(Config->SerialConfig->CheckCarrier && !Config->SerialConfig->DirectConnection);
  1700.  
  1701.     return(Result);
  1702. }
  1703.  
  1704.     /* xpr_gets(STRPTR Prompt,STRPTR Buffer):
  1705.      *
  1706.      *    Prompt the user for string input.
  1707.      */
  1708.  
  1709. LONG SAVE_DS ASM
  1710. xpr_gets(REG(a0) STRPTR Prompt,REG(a1) STRPTR Buffer)
  1711. {
  1712.     enum    {    GAD_OK=1,GAD_CANCEL,GAD_STRING };
  1713.  
  1714.     UBYTE LocalBuffer[256];
  1715.     LayoutHandle *Handle;
  1716.     LONG Success;
  1717.  
  1718.     DB(kprintf("xpr_gets(\"%s\",\"%s\")\n",Prompt,Buffer));
  1719.  
  1720.     Success = FALSE;
  1721.  
  1722.     LimitedStrcpy(sizeof(LocalBuffer),LocalBuffer,Buffer);
  1723.  
  1724.     if(!Prompt)
  1725.         Prompt = LocaleString(MSG_TERMXPR_INPUT_REQUIRED_TXT);
  1726.  
  1727.     if(Handle = LT_CreateHandleTags(Window->WScreen,
  1728.         LAHN_LocaleHook,    &LocaleHook,
  1729.     TAG_DONE))
  1730.     {
  1731.         struct Window *PanelWindow;
  1732.  
  1733.         LT_New(Handle,
  1734.             LA_Type,VERTICAL_KIND,
  1735.         TAG_DONE);
  1736.         {
  1737.             LT_New(Handle,
  1738.                 LA_Type,        VERTICAL_KIND,
  1739.                 LA_LabelText,    Prompt,
  1740.             TAG_DONE);
  1741.             {
  1742.                 LT_New(Handle,
  1743.                     LA_Type,    STRING_KIND,
  1744.                     LA_STRPTR,    LocalBuffer,
  1745.                     LA_ID,        GAD_STRING,
  1746.                     LA_Chars,    30,
  1747.                 TAG_DONE);
  1748.  
  1749.                 LT_EndGroup(Handle);
  1750.             }
  1751.  
  1752.             LT_New(Handle,
  1753.                 LA_Type,VERTICAL_KIND,
  1754.             TAG_DONE);
  1755.             {
  1756.                 LT_New(Handle,
  1757.                     LA_Type,        XBAR_KIND,
  1758.                     LAXB_FullSize,    TRUE,
  1759.                 TAG_DONE);
  1760.  
  1761.                 LT_EndGroup(Handle);
  1762.             }
  1763.  
  1764.             LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1765.                 LAGR_SameSize,    TRUE,
  1766.                 LAGR_Spread,    TRUE,
  1767.             TAG_DONE);
  1768.             {
  1769.                 LT_New(Handle,
  1770.                     LA_Type,        BUTTON_KIND,
  1771.                     LA_LabelID,        MSG_TERMXPR_OKAY_GAD,
  1772.                     LA_ID,            GAD_OK,
  1773.                     LABT_ReturnKey,    TRUE,
  1774.                     LABT_ExtraFat,    TRUE,
  1775.                 TAG_DONE);
  1776.  
  1777.                 LT_New(Handle,
  1778.                     LA_Type,        BUTTON_KIND,
  1779.                     LA_LabelID,        MSG_GLOBAL_CANCEL_GAD,
  1780.                     LA_ID,            GAD_CANCEL,
  1781.                     LABT_EscKey,    TRUE,
  1782.                     LABT_ExtraFat,    TRUE,
  1783.                 TAG_DONE);
  1784.  
  1785.                 LT_EndGroup(Handle);
  1786.             }
  1787.         }
  1788.  
  1789.         if(PanelWindow = LT_Build(Handle,
  1790.             LAWN_TitleText,        LocaleString(MSG_GLOBAL_ENTER_TEXT_TXT),
  1791.             LAWN_HelpHook,        &GuideHook,
  1792.             LAWN_Parent,        Window,
  1793.             WA_DepthGadget,        TRUE,
  1794.             WA_DragBar,            TRUE,
  1795.             WA_RMBTrap,            TRUE,
  1796.             WA_Activate,        TRUE,
  1797.         TAG_DONE))
  1798.         {
  1799.             struct IntuiMessage *Message;
  1800.             ULONG MsgClass,MsgQualifier;
  1801.             struct Gadget *MsgGadget;
  1802.             UWORD MsgCode;
  1803.             BOOL Done;
  1804.  
  1805.             PushWindow(PanelWindow);
  1806.  
  1807.             LT_ShowWindow(Handle,TRUE);
  1808.  
  1809.             LT_Activate(Handle,GAD_STRING);
  1810.  
  1811.             Done = FALSE;
  1812.  
  1813.             do
  1814.             {
  1815.                 if(Wait(PORTMASK(PanelWindow->UserPort) | SIG_BREAK) & SIG_BREAK)
  1816.                     break;
  1817.  
  1818.                 while(Message = (struct IntuiMessage *)GT_GetIMsg(PanelWindow->UserPort))
  1819.                 {
  1820.                     MsgClass        = Message->Class;
  1821.                     MsgQualifier    = Message->Qualifier;
  1822.                     MsgCode            = Message->Code;
  1823.                     MsgGadget        = (struct Gadget *)Message->IAddress;
  1824.  
  1825.                     GT_ReplyIMsg(Message);
  1826.  
  1827.                     LT_HandleInput(Handle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1828.  
  1829.                     if(MsgClass == IDCMP_GADGETUP)
  1830.                     {
  1831.                         switch(MsgGadget->GadgetID)
  1832.                         {
  1833.                             case GAD_STRING:
  1834.  
  1835.                                 if(MsgCode == '\r')
  1836.                                 {
  1837.                                     if(strcmp(Buffer,LocalBuffer))
  1838.                                         NewOptions = TRUE;
  1839.  
  1840.                                     strcpy(Buffer,LocalBuffer);
  1841.  
  1842.                                     Success = Done = TRUE;
  1843.  
  1844.                                     LT_PressButton(Handle,GAD_OK);
  1845.                                 }
  1846.  
  1847.                                 break;
  1848.  
  1849.                             case GAD_OK:
  1850.  
  1851.                                 LT_UpdateStrings(Handle);
  1852.  
  1853.                                 if(strcmp(Buffer,LocalBuffer))
  1854.                                     NewOptions = TRUE;
  1855.  
  1856.                                 strcpy(Buffer,LocalBuffer);
  1857.  
  1858.                                 Success = Done = TRUE;
  1859.  
  1860.                                 break;
  1861.  
  1862.                             case GAD_CANCEL:
  1863.  
  1864.                                 Done = TRUE;
  1865.                                 break;
  1866.                         }
  1867.                     }
  1868.                 }
  1869.             }
  1870.             while(!Done);
  1871.  
  1872.             PopWindow();
  1873.         }
  1874.  
  1875.         LT_DeleteHandle(Handle);
  1876.     }
  1877.  
  1878.     return(Success);
  1879. }
  1880.  
  1881.     /* xpr_setserial(LONG Status):
  1882.      *
  1883.      *    Set/read the serial status (parameters).
  1884.      */
  1885.  
  1886. LONG SAVE_DS ASM
  1887. xpr_setserial(REG(d0) LONG Status)
  1888. {
  1889.     DB(kprintf("xpr_setserial(0x%08lx)\n",Status));
  1890.  
  1891.     if(WriteRequest)
  1892.     {
  1893.         STATIC ULONG XprBauds[12] =
  1894.         {
  1895.                110,
  1896.                300,
  1897.               1200,
  1898.               2400,
  1899.               4800,
  1900.               9600,
  1901.              19200,
  1902.              31250,
  1903.              38400,
  1904.              57600,
  1905.              76800,
  1906.             115200
  1907.         };
  1908.  
  1909.         LONG Return,i;
  1910.  
  1911.         StopSerialRead();
  1912.         StopSerialWrite();
  1913.  
  1914.         DoSerialCmd(SDCMD_QUERY);
  1915.  
  1916.         Return = WriteRequest->io_SerFlags & 0xFF;
  1917.  
  1918.         if(WriteRequest->io_ExtFlags & SEXTF_MSPON)
  1919.             Return |= ST_PARTYMARKON;
  1920.  
  1921.         if(WriteRequest->io_ExtFlags & SEXTF_MARK)
  1922.             Return |= ST_PARTYMARK;
  1923.  
  1924.         if(WriteRequest->io_StopBits == 2)
  1925.             Return |= ST_2BITS;
  1926.  
  1927.         if(WriteRequest->io_ReadLen == 7)
  1928.             Return |= ST_READ7;
  1929.  
  1930.         if(WriteRequest->io_WriteLen == 7)
  1931.             Return |= ST_WRITE7;
  1932.  
  1933.         for(i = 0 ; i < 12 ; i++)
  1934.         {
  1935.             if(XprBauds[i] >= WriteRequest->io_Baud)
  1936.             {
  1937.                 Return |= (i << 16);
  1938.  
  1939.                 break;
  1940.             }
  1941.         }
  1942.  
  1943.             /* Just in case no match was to be made... */
  1944.  
  1945.         if(!(Return & 0xFFFF0000))
  1946.             Return |= (11 << 16);
  1947.  
  1948.             /* Update serial parameters, don't change
  1949.              * the baud rate however.
  1950.              */
  1951.  
  1952.         if(Status != -1)
  1953.         {
  1954.             WriteRequest->io_SerFlags = Status & 0xFF;
  1955.             WriteRequest->io_ExtFlags = 0;
  1956.  
  1957.             if(Status & ST_PARTYMARKON)
  1958.                 WriteRequest->io_ExtFlags |= SEXTF_MSPON;
  1959.  
  1960.             if(Status & ST_PARTYMARK)
  1961.                 WriteRequest->io_ExtFlags |= SEXTF_MARK;
  1962.  
  1963.             if(Status & ST_2BITS)
  1964.                 WriteRequest->io_StopBits = 2;
  1965.             else
  1966.                 WriteRequest->io_StopBits = 1;
  1967.  
  1968.             if(Status & ST_READ7)
  1969.                 WriteRequest->io_ReadLen = 7;
  1970.             else
  1971.                 WriteRequest->io_ReadLen = 8;
  1972.  
  1973.             if(Status & ST_WRITE7)
  1974.                 WriteRequest->io_WriteLen = 7;
  1975.             else
  1976.                 WriteRequest->io_WriteLen = 8;
  1977.  
  1978.             WriteRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  1979.             DoIO((struct IORequest *)WriteRequest);
  1980.  
  1981.             CopyMem(WriteRequest,ReadRequest,sizeof(struct IOExtSer));
  1982.  
  1983.             ReadRequest->IOSer.io_Message.mn_ReplyPort = ReadPort;
  1984.  
  1985.             CopyWriteFlags();
  1986.  
  1987.             if(WriteRequest->io_SerFlags & SERF_7WIRE)
  1988.             {
  1989.                 if(Config->SerialConfig->HandshakingProtocol == HANDSHAKING_NONE)
  1990.                     Config->SerialConfig->HandshakingProtocol = HANDSHAKING_RTSCTS_DSR;
  1991.             }
  1992.             else
  1993.             {
  1994.                 if(Config->SerialConfig->HandshakingProtocol != HANDSHAKING_NONE)
  1995.                     Config->SerialConfig->HandshakingProtocol = HANDSHAKING_NONE;
  1996.             }
  1997.         }
  1998.  
  1999.         return(Return);
  2000.     }
  2001.     else
  2002.         return(-1);
  2003. }
  2004.  
  2005.     /* xpr_ffirst(STRPTR Buffer,STRPTR Pattern):
  2006.      *
  2007.      *    Batch file upload: find the first matching file and return
  2008.      *    its name.
  2009.      */
  2010.  
  2011. LONG SAVE_DS ASM
  2012. xpr_ffirst(REG(a0) STRPTR Buffer,REG(a1) STRPTR UnusedPattern)
  2013. {
  2014.     DB(kprintf("xpr_ffirst(0x%08lx,\"%s\")\n",Buffer,Pattern));
  2015.  
  2016.     if(FileTransferInfo)
  2017.     {
  2018.         FileTransferInfo->DoneSize    = 0;
  2019.         FileTransferInfo->DoneFiles    = 0;
  2020.  
  2021.         FileTransferInfo->CurrentFile    = (struct FileTransferNode *)FileTransferInfo->FileList.mlh_Head;
  2022.         FileTransferInfo->CurrentSize    = FileTransferInfo->CurrentFile->Size;
  2023.  
  2024.         if(Config->TransferConfig->MangleFileNames)
  2025.         {
  2026.             UBYTE LocalName[MAX_FILENAME_LENGTH],*Char;
  2027.  
  2028.             LimitedStrcpy(sizeof(OriginalName),OriginalName,FileTransferInfo->CurrentFile->Name);
  2029.  
  2030.             ShrinkName(FilePart(FileTransferInfo->CurrentFile->Name),LocalName,12,TRUE);
  2031.  
  2032.             strcpy(Buffer,FileTransferInfo->CurrentFile->Name);
  2033.  
  2034.             Char = PathPart(Buffer);
  2035.             *Char = 0;
  2036.  
  2037.             AddPart(Buffer,LocalName,MAX_FILENAME_LENGTH);
  2038.  
  2039.             LimitedStrcpy(sizeof(ShrunkenName),ShrunkenName,Buffer);
  2040.         }
  2041.         else
  2042.         {
  2043.             OriginalName[0] = 0;
  2044.  
  2045.             strcpy(Buffer,FileTransferInfo->CurrentFile->Name);
  2046.         }
  2047.  
  2048.         return(1);
  2049.     }
  2050.     else
  2051.         return(0);
  2052. }
  2053.  
  2054.     /* xpr_fnext(LONG OldState,STRPTR Buffer,STRPTR Pattern):
  2055.      *
  2056.      *    Batch file upload: find the next matching file
  2057.      *    - if any - and return its name.
  2058.      */
  2059.  
  2060. LONG SAVE_DS ASM
  2061. xpr_fnext(REG(d0) LONG UnusedOldState,REG(a0) STRPTR Buffer,REG(a1) STRPTR UnusedPattern)
  2062. {
  2063.     DB(kprintf("xpr_fnext(%ld,0x%08lx,\"%s\")\n",OldState,Buffer,Pattern));
  2064.  
  2065.     if(FileTransferInfo)
  2066.     {
  2067.         if(FileTransferInfo->CurrentFile->MinNode.mln_Succ->mln_Succ)
  2068.         {
  2069.             FileTransferInfo->DoneSize    += FileTransferInfo->CurrentSize;
  2070.             FileTransferInfo->DoneFiles    += 1;
  2071.  
  2072.             FileTransferInfo->CurrentFile  = (struct FileTransferNode *)FileTransferInfo->CurrentFile->MinNode.mln_Succ;
  2073.             FileTransferInfo->CurrentSize  = FileTransferInfo->CurrentFile->Size;
  2074.  
  2075.             if(Config->TransferConfig->MangleFileNames)
  2076.             {
  2077.                 UBYTE LocalName[MAX_FILENAME_LENGTH],*Char;
  2078.  
  2079.                 LimitedStrcpy(sizeof(OriginalName),OriginalName,FileTransferInfo->CurrentFile->Name);
  2080.  
  2081.                 ShrinkName(FilePart(FileTransferInfo->CurrentFile->Name),LocalName,12,TRUE);
  2082.  
  2083.                 strcpy(Buffer,FileTransferInfo->CurrentFile->Name);
  2084.  
  2085.                 Char = PathPart(Buffer);
  2086.  
  2087.                 *Char = 0;
  2088.  
  2089.                 AddPart(Buffer,LocalName,MAX_FILENAME_LENGTH);
  2090.  
  2091.                 LimitedStrcpy(sizeof(ShrunkenName),ShrunkenName,Buffer);
  2092.             }
  2093.             else
  2094.             {
  2095.                 OriginalName[0] = 0;
  2096.  
  2097.                 strcpy(Buffer,FileTransferInfo->CurrentFile->Name);
  2098.             }
  2099.  
  2100.             return(1);
  2101.         }
  2102.     }
  2103.  
  2104.     return(0);
  2105. }
  2106.  
  2107.     /* xpr_finfo(STRPTR FileName,LONG InfoType):
  2108.      *
  2109.      *    Return information on a given file.
  2110.      */
  2111.  
  2112. LONG SAVE_DS ASM
  2113. xpr_finfo(REG(a0) STRPTR FileName,REG(d0) LONG InfoType)
  2114. {
  2115.     UBYTE RealName[MAX_FILENAME_LENGTH];
  2116.  
  2117.     DB(kprintf("xpr_finfo(\"%s\",%ld)\n",FileName,InfoType));
  2118.  
  2119.     switch(InfoType)
  2120.     {
  2121.             /* Return the file size. */
  2122.  
  2123.         case 1:
  2124.  
  2125.             if(OriginalName[0])
  2126.             {
  2127.                 if(!Stricmp(ShrunkenName,FileName))
  2128.                     FileName = NewFileName(OriginalName,RealName,sizeof(RealName));
  2129.                 else
  2130.                     FileName = NewFileName(FileName,RealName,sizeof(RealName));
  2131.             }
  2132.             else
  2133.                 FileName = NewFileName(FileName,RealName,sizeof(RealName));
  2134.  
  2135.             return(GetFileSize(FileName));
  2136.  
  2137.             /* Return the file transfer mode. */
  2138.  
  2139.         case 2:
  2140.  
  2141.             return(BinaryTransfer ? 1 : 2);
  2142.  
  2143.             /* Ignore the rest. */
  2144.  
  2145.         default:
  2146.  
  2147.             return(0);
  2148.     }
  2149. }
  2150.  
  2151.     /* xpr_options(LONG NumOpts,struct xpr_option **Opts):
  2152.      *
  2153.      *    Provide a more polished user interface to set the
  2154.      *    transfer protocol options.
  2155.      */
  2156.  
  2157. ULONG SAVE_DS ASM
  2158. xpr_options(REG(d0) LONG NumOpts,REG(a0) struct xpr_option **Opts)
  2159. {
  2160.     DB(kprintf("xpr_options(%ld,0x%08lx)\n",NumOpts,Opts));
  2161.  
  2162.     if(NumOpts && Opts)
  2163.     {
  2164.         enum    {    GAD_Use=1,GAD_Cancel,GAD_Special };
  2165.  
  2166.         LayoutHandle *Handle;
  2167.         ULONG Flags;
  2168.  
  2169.         Flags = NULL;
  2170.  
  2171.             /* We only have 32 bits! */
  2172.  
  2173.         if(NumOpts > 32)
  2174.             NumOpts = 32;
  2175.  
  2176.         if(Handle = LT_CreateHandleTags(Window->WScreen,
  2177.             LAHN_LocaleHook,    &LocaleHook,
  2178.         TAG_DONE))
  2179.         {
  2180.             struct Window *PanelWindow;
  2181.             LONG i,Split;
  2182.  
  2183.             if(NumOpts > 16)
  2184.                 Split = NumOpts / 2;
  2185.             else
  2186.                 Split = -1;
  2187.  
  2188.             LT_New(Handle,
  2189.                 LA_Type,VERTICAL_KIND,
  2190.             TAG_DONE);
  2191.             {
  2192.                 LT_New(Handle,
  2193.                     LA_Type,HORIZONTAL_KIND,
  2194.                 TAG_DONE);
  2195.                 {
  2196.                     LT_New(Handle,
  2197.                         LA_Type,VERTICAL_KIND,
  2198.                     TAG_DONE);
  2199.                     {
  2200.                         for(i = 0 ; i < NumOpts ; i++)
  2201.                         {
  2202.                             if(Opts[i])
  2203.                             {
  2204.                                 switch(Opts[i]->xpro_type)
  2205.                                 {
  2206.                                     case XPRO_BOOLEAN:
  2207.  
  2208.                                         LT_New(Handle,
  2209.                                             LA_Type,        CHECKBOX_KIND,
  2210.                                             LA_LabelText,    Opts[i]->xpro_description,
  2211.                                             LA_ID,            GAD_Special + i,
  2212.                                             GTCB_Checked,    String2Boolean(Opts[i]->xpro_value),
  2213.                                         TAG_DONE);
  2214.  
  2215.                                         break;
  2216.  
  2217.                                     case XPRO_LONG:
  2218.  
  2219.                                         LT_New(Handle,
  2220.                                             LA_Type,                INTEGER_KIND,
  2221.                                             LA_LabelText,            Opts[i]->xpro_description,
  2222.                                             LA_ID,                    GAD_Special + i,
  2223.                                             LA_Chars,                15,
  2224.                                             GTIN_Number,            Atol(Opts[i]->xpro_value),
  2225.                                             LAIN_UseIncrementers,    TRUE,
  2226.                                         TAG_DONE);
  2227.  
  2228.                                         break;
  2229.  
  2230.                                     case XPRO_STRING:
  2231.  
  2232.                                         LT_New(Handle,
  2233.                                             LA_Type,        STRING_KIND,
  2234.                                             LA_LabelText,    Opts[i]->xpro_description,
  2235.                                             LA_ID,            GAD_Special + i,
  2236.                                             LA_Chars,        15,
  2237.                                             GTST_String,    Opts[i]->xpro_value,
  2238.                                             GTST_MaxChars,    Opts[i]->xpro_length - 1,
  2239.                                         TAG_DONE);
  2240.  
  2241.                                         break;
  2242.  
  2243.                                     case XPRO_COMMPAR:
  2244.  
  2245.                                         LT_New(Handle,
  2246.                                             LA_Type,        STRING_KIND,
  2247.                                             LA_LabelText,    Opts[i]->xpro_description,
  2248.                                             LA_ID,            GAD_Special + i,
  2249.                                             LA_Chars,        15,
  2250.                                             LA_HighLabel,    TRUE,
  2251.                                             GTST_String,    Opts[i]->xpro_value,
  2252.                                             GTST_MaxChars,    Opts[i]->xpro_length - 1,
  2253.                                         TAG_DONE);
  2254.  
  2255.                                         break;
  2256.  
  2257.                                     case XPRO_HEADER:
  2258.  
  2259.                                         LT_New(Handle,
  2260.                                             LA_Type,        TEXT_KIND,
  2261.                                             LA_LabelText,    Opts[i]->xpro_description,
  2262.                                             LA_HighLabel,    TRUE,
  2263.                                             GTTX_Text,        " ",
  2264.                                         TAG_DONE);
  2265.  
  2266.                                         break;
  2267.  
  2268.                                     case XPRO_COMMAND:
  2269.  
  2270.                                         LT_New(Handle,
  2271.                                             LA_Type,        BUTTON_KIND,
  2272.                                             LA_LabelText,    Opts[i]->xpro_description,
  2273.                                             LA_ID,            GAD_Special + i,
  2274.                                             LA_Chars,        15,
  2275.                                         TAG_DONE);
  2276.  
  2277.                                         break;
  2278.                                 }
  2279.                             }
  2280.  
  2281.                             if(i == Split)
  2282.                             {
  2283.                                 LT_EndGroup(Handle);
  2284.  
  2285.                                 LT_New(Handle,
  2286.                                     LA_Type,VERTICAL_KIND,
  2287.                                 TAG_DONE);
  2288.                                 {
  2289.                                     LT_New(Handle,
  2290.                                         LA_Type,YBAR_KIND,
  2291.                                     TAG_DONE);
  2292.  
  2293.                                     LT_EndGroup(Handle);
  2294.                                 }
  2295.  
  2296.                                 LT_New(Handle,
  2297.                                     LA_Type,VERTICAL_KIND,
  2298.                                 TAG_DONE);
  2299.                             }
  2300.                         }
  2301.  
  2302.                         LT_EndGroup(Handle);
  2303.                     }
  2304.  
  2305.                     LT_EndGroup(Handle);
  2306.                 }
  2307.  
  2308.                 LT_New(Handle,
  2309.                     LA_Type,VERTICAL_KIND,
  2310.                 TAG_DONE);
  2311.                 {
  2312.                     LT_New(Handle,
  2313.                         LA_Type,        XBAR_KIND,
  2314.                         LAXB_FullSize,    TRUE,
  2315.                     TAG_DONE);
  2316.  
  2317.                     LT_EndGroup(Handle);
  2318.                 }
  2319.  
  2320.                 LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  2321.                     LAGR_SameSize,    TRUE,
  2322.                     LAGR_Spread,    TRUE,
  2323.                 TAG_DONE);
  2324.                 {
  2325.                     LT_New(Handle,
  2326.                         LA_Type,        BUTTON_KIND,
  2327.                         LA_LabelID,        MSG_GLOBAL_SAVE_TXT,
  2328.                         LA_ID,            GAD_Use,
  2329.                         LABT_ReturnKey,    TRUE,
  2330.                         LABT_ExtraFat,    TRUE,
  2331.                     TAG_DONE);
  2332.  
  2333.                     LT_New(Handle,
  2334.                         LA_Type,        BUTTON_KIND,
  2335.                         LA_LabelID,        MSG_GLOBAL_CANCEL_GAD,
  2336.                         LA_ID,            GAD_Cancel,
  2337.                         LABT_EscKey,    TRUE,
  2338.                         LABT_ExtraFat,    TRUE,
  2339.                     TAG_DONE);
  2340.  
  2341.                     LT_EndGroup(Handle);
  2342.                 }
  2343.  
  2344.                 LT_EndGroup(Handle);
  2345.             }
  2346.  
  2347.             if(PanelWindow = LT_Build(Handle,
  2348.                 LAWN_TitleText,        OptionTitle ? OptionTitle : LocaleString(MSG_TERMXPR_TRANSFER_OPTIONS_TXT),
  2349.                 LAWN_HelpHook,        &GuideHook,
  2350.                 LAWN_Parent,        Window,
  2351.                 WA_DepthGadget,        TRUE,
  2352.                 WA_DragBar,            TRUE,
  2353.                 WA_RMBTrap,            TRUE,
  2354.                 WA_Activate,        TRUE,
  2355.             TAG_DONE))
  2356.             {
  2357.                 struct IntuiMessage    *Message;
  2358.                 ULONG MsgClass,MsgQualifier;
  2359.                 struct Gadget *MsgGadget;
  2360.                 BOOL CheckFlags;
  2361.                 UWORD MsgCode;
  2362.                 BOOL Done;
  2363.  
  2364.                 CheckFlags = FALSE;
  2365.  
  2366.                 PushWindow(PanelWindow);
  2367.  
  2368.                 LT_ShowWindow(Handle,TRUE);
  2369.  
  2370.                 Done = FALSE;
  2371.  
  2372.                 do
  2373.                 {
  2374.                     if(Wait(PORTMASK(PanelWindow->UserPort) | SIG_BREAK) & SIG_BREAK)
  2375.                         break;
  2376.  
  2377.                     while(Message = (struct IntuiMessage *)GT_GetIMsg(PanelWindow->UserPort))
  2378.                     {
  2379.                         MsgClass        = Message->Class;
  2380.                         MsgQualifier    = Message->Qualifier;
  2381.                         MsgCode            = Message->Code;
  2382.                         MsgGadget        = (struct Gadget *)Message->IAddress;
  2383.  
  2384.                         GT_ReplyIMsg(Message);
  2385.  
  2386.                         LT_HandleInput(Handle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  2387.  
  2388.                         if(MsgClass == IDCMP_GADGETUP)
  2389.                         {
  2390.                             switch(MsgGadget->GadgetID)
  2391.                             {
  2392.                                 case GAD_Use:
  2393.  
  2394.                                     Done = CheckFlags = TRUE;
  2395.                                     break;
  2396.  
  2397.                                 case GAD_Cancel:
  2398.  
  2399.                                     Done = TRUE;
  2400.                                     break;
  2401.  
  2402.                                 default:
  2403.  
  2404.                                     if(MsgGadget->GadgetID - GAD_Special < NumOpts)
  2405.                                     {
  2406.                                         i = MsgGadget->GadgetID - GAD_Special;
  2407.  
  2408.                                         if(Opts[i]->xpro_type == XPRO_COMMAND || (Opts[i]->xpro_type == XPRO_COMMPAR && MsgCode != '\t'))
  2409.                                         {
  2410.                                             Flags = (1L << i);
  2411.  
  2412.                                             XPRCommandSelected = Done = CheckFlags = TRUE;
  2413.                                         }
  2414.                                     }
  2415.  
  2416.                                     break;
  2417.                             }
  2418.                         }
  2419.                     }
  2420.                 }
  2421.                 while(!Done);
  2422.  
  2423.                 PopWindow();
  2424.  
  2425.                 if(CheckFlags)
  2426.                 {
  2427.                     LT_LockWindow(PanelWindow);
  2428.  
  2429.                     for(i = 0 ; i < NumOpts ; i++)
  2430.                     {
  2431.                         if(Opts[i])
  2432.                         {
  2433.                             switch(Opts[i]->xpro_type)
  2434.                             {
  2435.                                 case XPRO_BOOLEAN:
  2436.  
  2437.                                     if(LT_GetAttributes(Handle,GAD_Special + i,TAG_DONE) != String2Boolean(Opts[i]->xpro_value))
  2438.                                     {
  2439.                                         Flags |= (1L << i);
  2440.  
  2441.                                         if(LT_GetAttributes(Handle,GAD_Special + i,TAG_DONE))
  2442.                                             strcpy(Opts[i]->xpro_value,"yes");
  2443.                                         else
  2444.                                             strcpy(Opts[i]->xpro_value,"no");
  2445.  
  2446.                                         NewOptions = TRUE;
  2447.                                     }
  2448.  
  2449.                                     break;
  2450.  
  2451.                                 case XPRO_LONG:
  2452.  
  2453.                                     if(Atol(Opts[i]->xpro_value) != LT_GetAttributes(Handle,GAD_Special + i,TAG_DONE))
  2454.                                     {
  2455.                                         Flags |= (1L << i);
  2456.  
  2457.                                         SPrintf(Opts[i]->xpro_value,"%ld",LT_GetAttributes(Handle,GAD_Special + i,TAG_DONE));
  2458.  
  2459.                                         NewOptions = TRUE;
  2460.                                     }
  2461.  
  2462.                                     break;
  2463.  
  2464.                                 case XPRO_STRING:
  2465.  
  2466.                                     if(strcmp(Opts[i]->xpro_value,LT_GetString(Handle,GAD_Special + i)))
  2467.                                     {
  2468.                                         Flags |= (1L << i);
  2469.  
  2470.                                         strcpy(Opts[i]->xpro_value,LT_GetString(Handle,GAD_Special + i));
  2471.  
  2472.                                         NewOptions = TRUE;
  2473.                                     }
  2474.  
  2475.                                     break;
  2476.                             }
  2477.                         }
  2478.                     }
  2479.  
  2480.                     LT_UnlockWindow(PanelWindow);
  2481.                 }
  2482.                 else
  2483.                     Flags = NULL;
  2484.             }
  2485.  
  2486.             LT_DeleteHandle(Handle);
  2487.         }
  2488.  
  2489.         return(Flags);
  2490.     }
  2491.     else
  2492.         return(NULL);
  2493. }
  2494.  
  2495.     /* xpr_unlink(STRPTR FileName):
  2496.      *
  2497.      *    Remove (delete) a given file.
  2498.      */
  2499.  
  2500. LONG SAVE_DS ASM
  2501. xpr_unlink(REG(a0) STRPTR FileName)
  2502. {
  2503.     DB(kprintf("xpr_unlink(\"%s\")\n",FileName));
  2504.  
  2505.         /* Sorry, but it is far too dangerous to let the protocol
  2506.          * remove any files with path name substitution enabled.
  2507.          * The protocol could accidentally hit the wrong file.
  2508.          */
  2509.  
  2510.     if(!Config->TransferConfig->OverridePath)
  2511.     {
  2512.         if(OriginalName[0])
  2513.         {
  2514.             if(!Stricmp(ShrunkenName,FileName))
  2515.                 FileName = OriginalName;
  2516.         }
  2517.  
  2518.         if(DeleteFile(FileName))
  2519.         {
  2520.             LogAction(LocaleString(MSG_TERMXPR_LOGMSG_DELETE_FILE_TXT),FilePart(FileName));
  2521.  
  2522.             return(0);
  2523.         }
  2524.     }
  2525.  
  2526.     return(-1);
  2527. }
  2528.  
  2529.     /* xpr_squery():
  2530.      *
  2531.      *    Check how many characters are present in the serial buffer.
  2532.      */
  2533.  
  2534. LONG SAVE_DS
  2535. xpr_squery()
  2536. {
  2537.     DB(kprintf("xpr_squery()\n"));
  2538.  
  2539.     if(WriteRequest)
  2540.     {
  2541.         ULONG Waiting;
  2542.         UWORD Status;
  2543.  
  2544.         GetSerialInfo(&Waiting,&Status);
  2545.  
  2546.             /* Return error if carrier is lost. */
  2547.  
  2548.         if(!CheckForCarrierLoss(Status))
  2549.             return((LONG)Waiting);
  2550.     }
  2551.  
  2552.     return(-1);
  2553. }
  2554.  
  2555.     /* xpr_getptr(LONG InfoType):
  2556.      *
  2557.      *    Return a pointer to the term custom screen.
  2558.      */
  2559.  
  2560. LONG SAVE_DS ASM
  2561. xpr_getptr(REG(d0) LONG InfoType)
  2562. {
  2563.     DB(kprintf("xpr_getptr(%ld)\n",InfoType));
  2564.  
  2565.     if(InfoType == 1)
  2566.         return((LONG)Window->WScreen);
  2567.     else
  2568.         return(-1);
  2569. }
  2570.  
  2571.     /* xpr_stealopts(STRPTR Prompt,STRPTR Buffer):
  2572.      *
  2573.      *    Steal the contents of the options buffer (replacement
  2574.      *    for xpr_gets).
  2575.      */
  2576.  
  2577. LONG SAVE_DS ASM
  2578. xpr_stealopts(REG(a0) STRPTR UnusedPrompt,REG(a1) STRPTR Buffer)
  2579. {
  2580.     DB(kprintf("xpr_stealopts(\"%s\",\"%s\")\n",Prompt,Buffer));
  2581.  
  2582.     if(Buffer)
  2583.         LimitedStrcpy(sizeof(ProtocolOptsBuffer),ProtocolOptsBuffer,Buffer);
  2584.  
  2585.     return(1);
  2586. }
  2587.